package com.feonix.common.basedao;

import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.support.lob.LobHandler;

import com.feonix.common.annotation.ColumnType;
import com.feonix.common.util.JsonUtil;
import com.feonix.common.util.ReflectionUtils;
import com.feonix.common.util.StringUtil;

public class EntityRowMap<T> extends BeanPropertyRowMapper<T> {
	protected final Log logger = LogFactory.getLog(super.getClass());
	private Class<T> clazz;
	private Entity entity = null;

	private ResultSetMetaData resultSetMetaData = null;

	private int columnCount = 0;
	protected LobHandler lobHandler;

	public EntityRowMap(Class<T> clazz) {
		this.clazz = clazz;
		this.entity = EntityManager.getEntity(this.clazz);
	}

	public T mapRow(ResultSet rs, int rowNum) throws SQLException {
		T t = null;
		if (this.entity == null) {
			return t;
		}

		try {
			t = this.clazz.newInstance();
			if (this.resultSetMetaData == null) {
				this.resultSetMetaData = rs.getMetaData();
				this.columnCount = this.resultSetMetaData.getColumnCount();
			}
			String columnLabel = null;
			Object value = null;
			String fieldName = null;
			Class<?> fieldType = null;
			EntityProperty entityProperty = null;
			for (int i = 1; i <= this.columnCount; ++i) {
				columnLabel = this.resultSetMetaData.getColumnLabel(i).toLowerCase();
				if (columnLabel.indexOf(".") > -1) {
					columnLabel = columnLabel.substring(columnLabel.indexOf(".") + 1);
				}
				value = rs.getObject(columnLabel);
				entityProperty = this.entity.getEntityProperty(columnLabel);
				if (entityProperty == null) {
					continue;
				}
				fieldType = entityProperty.getFieldType();
				fieldName = entityProperty.getFieldName();
				if (fieldType == null)
					continue;
				if (StringUtil.isEmpty(fieldName)) {
					continue;
				}
				if (Date.class.isAssignableFrom(fieldType)) {
					if (entityProperty.getColumnType() != null) {
						switch (entityProperty.getColumnType().ordinal() + 1) {
						case 2:
							value = rs.getTimestamp(columnLabel);
							break;
						case 1:
							value = rs.getDate(columnLabel);
							break;
						default:
							value = rs.getTimestamp(columnLabel);
							break;
						}
					} else {
						value = rs.getTimestamp(columnLabel);
					}
					ReflectionUtils.setFieldValue(t, fieldName, value);
				} else {
					if (value instanceof Blob)
						value = rs.getBytes(columnLabel);
					else if (value instanceof Clob) {
						value = rs.getString(columnLabel);
					}
					if (entityProperty.getColumnType() == ColumnType.JSON) {
						if (Collection.class.isAssignableFrom(entityProperty.getFieldType()))
							value = JsonUtil.StringToList(StringUtil.getString(value),
									new Class[] { entityProperty.getFieldType() });
						else {
							value = JsonUtil.StringToObject(StringUtil.getString(value), entityProperty.getFieldType());
						}
					}
					BeanUtils.setProperty(t, fieldName, value);
				}
			}
		} catch (Exception exception) {
			this.logger.error("row to object error", exception);
		}
		return t;
	}

}
